from Node import Node
from User import User
import logging
import os
import paramiko
import sys
import tempfile
import threading

class MySSHClient(paramiko.SSHClient):
## overload the exec_command method
    def exec_command(self, command, bufsize=-1,timeout=None):
        chan = self._transport.open_session()
        chan.settimeout(timeout)


        chan.exec_command(command)
        stdin = chan.makefile('wb', bufsize)


        stdout = chan.makefile('rb', bufsize)
        stderr = chan.makefile_stderr('rb', bufsize)
        exitStatus = chan.recv_exit_status()
        return stdin, stdout, stderr,exitStatus 
            



class SSH:
#
    """Connects and logs into the specified hostname. 
    Arguments that are not given are guessed from the environment.""" 

    ssh_live = False
    ssh = None
    sftp_live = False
    sftp = None
    
    def __init__(self,
                 hostname,
                 username = None,
                 password = None,
                 private_key = None,
                 port = 22,
                 ):
        self.ssh_live = False
        self.ssh = None
        self.sftp_live = False
        self.sftp = None
        self.transObj = None
        
     
#        self.logger = paramiko.util.logging.getLogger()
#        self.logger.setLevel(40)

        self.ssh = MySSHClient()
        self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        self.ssh_live = True
        self.ssh.connect(hostname,username=username, password=password,timeout=60,look_for_keys = False)

        self.transObj = self.ssh.get_transport()
        
        self.transObj.use_compression(True)
    
    
            
    def get(self, remotepath, localpath):
        """Copies a file between the remote host and the local host."""
      
        self.sftp = self.ssh.open_sftp()
        self.sftp.get(remotepath, localpath)
        self.sftp.close()
        
    def ReadFile(self,remotepath):
        fileArray = []
        logging.info("Reading "+remotepath)
        self.sftp = self.ssh.open_sftp()
        fileHandle = self.sftp.open(remotepath,'r')
        try:
            for line in fileHandle:
               fileArray.append(str(line))
        finally:
            fileHandle.close()

        return fileArray
        
        
        
    def AppendFile(self,remotepath,appendStr,sudo):
        
        
        self.sftp = self.ssh.open_sftp()
        
        if (sudo):
            fileAttributes = self.sftp.stat(remotepath)
            currentMode = fileAttributes.st_mode
            cmd = "sudo chmod o+w "+remotepath
            self.ssh.exec_command(cmd)
            fileAttributes = self.sftp.stat(remotepath)
            newMode = fileAttributes.st_mode
        
        
        fileHandle = self.sftp.open(remotepath,'a+')

       
        modified = False
        try: 
            for line in fileHandle:
               if(appendStr.upper() in str(line).upper()):
                    modified = True
            if (not modified):
                fileHandle.write(appendStr)
                self.sftp.close()
        except Exception,err:
            logging.error("Could Not Modify "+remotepath)
            
        if (sudo):
            cmd = "sudo chmod "+ str(oct(currentMode))[2:] +" "+remotepath
            self.ssh.exec_command(cmd)
            fileAttributes = self.sftp.stat(remotepath)    
            
            
            
    def CreateFile(self,remotepath,fileText):
        
        
        self.sftp = self.ssh.open_sftp()
        fileHandle = self.sftp.open(remotepath,'w')
        try: 
            for line in fileText:
                fileHandle.write(line)
        
            self.sftp.close()
        except Exception,err:
            logging.error("Could Not Modify "+remotepath)
    
        

        
    def put(self, localpath, remotepath,makedir,sudo):
        """Copies a file between the local host and the remote host."""
        remoteDirArray = remotepath.split("/")
        remoteDir = ""
        remoteDirArray.pop()
        for dir in (remoteDirArray):
            remoteDir = remoteDir + "/" + dir
        remoteDir = remoteDir[1:]
        self.sftp = self.ssh.open_sftp() 
      
        if (makedir):
            try:
                self.sftp.mkdir(remoteDir)
                logging.info("Created Directory "+ str(remoteDir))
            except Exception, err:
                logging.info("Directory " + str(remoteDir)+ " already Created")
                
          
        # FIX FOR NO SUDO-PUT
        #IF SUDO IS USED CHOWN FILE TEMPRARILY
        #First Get permissions
        #change
        #put
        #change back
        
       

        
        if (sudo) :
            try:
                fileAttributes = self.sftp.stat(remotepath)
            except IOError, e:
                if e[0] == 2:
                    cmd = "sudo touch "+remotepath
                    self.ssh.exec_command(cmd)
                    fileAttributes = self.sftp.stat(remotepath)
                    
            currentMode = fileAttributes.st_mode
            cmd = "sudo chmod o+w "+remotepath
            self.ssh.exec_command(cmd)
            fileAttributes = self.sftp.stat(remotepath)
            newMode = fileAttributes.st_mode
                
        self.sftp.put(localpath, remotepath)
        
        # FIX FOR NO SUDO-PUT
        if (sudo):
            cmd = "sudo chmod "+ str(oct(currentMode))[2:] +" "+remotepath
            self.ssh.exec_command(cmd)
            fileAttributes = self.sftp.stat(remotepath)
            
        self.sftp.close()

    def execute(self, command):
       
        """Execute the given commands on a remote machine."""
        
        (stdin,stdout,stderr) = self.ssh.exec_command(command)
        if stdout:
            return stdout
        else:
            return stderr

    def executeSt(self, command):
        """Execute the given commands on a remote machine."""
            
        
        stdin, stdout, stderr, exitStatus = self.ssh.exec_command(command,timeout=30)
        

        output = stdout.readlines()
        error = stderr.readlines()

        stdin.close()
        stdout.close()
        stderr.close()
      
        if exitStatus==0:
            return (exitStatus,output)
        else:
            return (exitStatus,str(output)+" "+str(error))

    


    def close(self):
        """Closes the connection and cleans up."""
        # Close SFTP Connection.
        if self.ssh_live:
            self.ssh.close()
            
       




